<!--- ATTRIBUTE VALIDATION --->
<!--- event name is required --->
<cfif NOT (isDefined("attributes.event") AND len(trim(attributes.event)))>
	<cfthrow detail="Cannot add event listener.  The event name was not specified.">
</cfif>

<!--- the caller must specify a CFC/method --->
<cfif NOT (isDefined("attributes.component") AND len(trim(attributes.component)))>
	<cfthrow detail="Cannot add event listener for #tuple.event#.  The listener component was not specified.">
</cfif>

<cfif NOT (isDefined("attributes.method") AND len(trim(attributes.method)))>
	<cfthrow detail="Cannot add event listener for #tuple.event#.  The listener method was not specified.">
</cfif>

<!--- END ATTRIBUTE VALIDATION --->

<cfset tuple = structNew()>

<cfif !isDefined("application.eventRegistry")>
	<!--- this is the struct that holds a reference to all event listeners --->
	<cfset application.eventRegistry = structNew()>
</cfif>

<cfset tuple.component = attributes.component>
<cfset tuple.method = attributes.method>

<cfif isDefined("attributes.threaded")>
	<cfif isBoolean(attributes.threaded)>
		<cfset tuple.threaded = attributes.threaded>
	<cfelse>
		<cfthrow detail="Cannot add event listener for #tuple.event#.  The 'threaded' attribute was not, and must be, a boolean value.">
	</cfif>
<cfelse>
	<cfset tuple.threaded = false>
</cfif>

<cfif !structKeyExists(application.eventRegistry, attributes.event)>	<!--- register this event if it is not already --->
	<!--- each event has an array of listeners --->
	<cfset structInsert(application.eventRegistry, attributes.event, #arrayNew(1)#)>
	<!--- if the situation warrants, this array could be sorted to affect the order in which listeners are notified of the event --->
</cfif>

<cfset arrayAppend(application.eventRegistry[attributes.event], tuple)>

<cfexit method="exittag">